iT邦幫忙

2024 iThome 鐵人賽

DAY 27
0
佛心分享-我的私藏工具箱

正則!好好表達系列 第 27

Spring Boot的RequestBody檢核

  • 分享至 

  • xImage
  •  

Spring Boot的validation套件提供豐富的資料檢核annotation,包括@Pattern支援Regex,不過秉持少引用一個套件就少一份處理弱掃的風險,加上有的檢核還真的是複雜,所以不引用validation自己手工做一個。
因此,一開始我就弱化了Controller角色,所有method都將@RequestBody當作字串處理,回應一律用Object,方便Value Object轉成JSON。

@RestController
@Slf4j
@RequiredArgsConstructor
public class CRMController {
    @Autowired
    private CRMService crmService;

    @PostMapping(value = "/getOldCust_Period", consumes = MediaType.APPLICATION_JSON_VALUE, produces = "application/json;charset=UTF-8")
    public ResponseEntity<Object> getOldCust_Period(@RequestBody String inputVO) {
        Object outputVO = this.crmService.getOldCust_Period(inputVO);
        return ResponseEntity.ok(outputVO);
    }
}

在客戶的弱掃軟體是Micro Focus,測試案例如下,會要求不得回覆HTTP Status 500。另一款弱掃軟體AppScan遇到以下測試個案例,會要求一律回HTTP Status 500

  • POST非JSON格式字串,比如XML、多媒體內容,甚至是上傳檔案。
  • POST長度過大的字串
  • POST JSON Key是不能識別的。比如{"is_admin": true}
  • Header的Content Type不是application/json
    • 這個Spring Boot可以處理,回應HTTP 400
  • POST JSON空值字串或是含特殊字元甚至是路徑等字串。
    • 在稽核需求下,只要JSON的key對,只是data值不符規範,依然記錄到Table裡。以便稽核Request端可能輸入錯誤值。
    • 在JSON的value就可以用Regex進行檢核。
      因此在Service類別檢核上分兩大塊,一個是格式,另一個是JSON Value,是故提供兩個method如下:

第一個validateJSON的檢核就包括了長度、JSON格式、JSON Key是否合法

private List<String> AFields = Arrays.asList(new String[]{"CUST_ID", "PROD_TYPE", "SEQ", "AMT"});

/**
 * 檢核A電文JSON字串有無失當
 * @param jsonStr
 * @return 回null表示正常
 */
private ESBErrorVO validateJSON(String jsonStr) {
    if (jsonStr != null && jsonStr.length() >= 2048) {
        ESBErrorVO errorVO = new ESBErrorVO();
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT(DenominatorService.EMSGTXT + ", 長度太長");
        return errorVO;
    }
    ObjectMapper mapper = new ObjectMapper();
    boolean valid = true;
    try {
        JsonNode rootNode = mapper.readTree(jsonStr);
        Iterator<String> fieldNames = rootNode.fieldNames();
        while (fieldNames.hasNext()) {
            String fieldName = fieldNames.next();
            if (!AFields.contains(fieldName)) {
                valid = false;
            }
        }
    } catch (Exception errJson) {
        ESBErrorVO errorVO = new ESBErrorVO();
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("非JSON格式");
        return errorVO;
    }
    if (!valid) {
        ESBErrorVO errorVO = new ESBErrorVO();
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("帶不合法欄位");
        return errorVO;
    }
    return null;
}

第二個檢核就針對每個欄位的value進行檢核,這時的ESBInputVO是透過Spring Boot的Jackson套件轉換,這原本是可以在Controller就可以透過@RequestBody ESBInputVO inputVO做掉:

ObjectMapper mapper = new ObjectMapper();
ESBInputVO inputVO = mapper.readValue(jsonStr, ESBInputVO.class);

validateInputVO的內容,其中checkIDType這個method是Day 1的內容,檢核客戶ID是哪一種類型,這需求就無法使用validation套件的@Pattern

/**
 * 檢核A上行電文欄位有無不當
 * @param inputVO
 * @return null表示沒錯誤
 */
private ESBErrorVO validateInputVO(ESBInputVO inputVO) {
    ESBErrorVO errorVO = new ESBErrorVO();
    StringBuffer sbErr = new StringBuffer();
    if (inputVO == null) {
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("上行電文為空");
        return errorVO;
    }
    String custId = inputVO.getCUST_ID();
    if (this.checkIDType(custId) == null) {
        sbErr.append("CUST_ID[").append(custId).append("]");
    }
    String prodType = inputVO.getPROD_TYPE();
    if (prodType == null || !prodType.matches("[1-6]")) {
        sbErr.append("PROD_TYPE[").append(prodType).append("]");
    }
    String amt = inputVO.getAMT();
    if (amt == null || !amt.matches("[0-9]{1,16}")) {
        sbErr.append("AMT[").append(amt).append("]");
    }
    String seq = inputVO.getSEQ();
    if (seq == null || !seq.matches("([0-9A-Za-z]){7,20}")) {
        sbErr.append("SEQ[").append(seq).append("]");
    }
    if (sbErr.length() > 0) {
        errorVO.setEMSGID("E005");
        errorVO.setEMSGTXT("上行電文欄位有誤:" + sbErr.toString());
        return errorVO;
    }
    return null;
}

上一篇
用Lambda統計Regex符合條件筆數
下一篇
用Perl產出過版清單貼上Excel
系列文
正則!好好表達30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言